﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "NewLevelType.h"
#include "DbObjectUtils.h"
#include "GbmpBuiltInCategoryUniIdentitiesNew.h"
#include "GbmpBuiltInParameterDefinitionsNew.h"
#include "GbmpDocUtils.h"
#include "IDocument.h"
#include "IElementBasicInformation.h"
#include "IElementParentReporter.h"
#include "IExternalDataComponent.h"
#include "IGenericElement.h"
#include "IGenericType.h"
#include "ILevel.h"
#include "IParameter.h"
#include "IParameterDefinitionLibrary.h"
#include "NewLevelHeaderTypeBehavior.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

DBOBJECT_DATA_DEFINE(NewLevelType)
{
    m_pOwnerElement = nullptr;
    SetIsStartHeaderVisible__(false);
    SetIsEndHeaderVisible__(true);
}

ILevelType* NewLevelType::Create(IDocument* pDoc, const std::wstring& name)
{
    NewLevelType* pNewLevelType = nullptr;
    IGenericType* pType = IGenericType::Create(pDoc, name);
    if (pType)
    {
        OwnerPtr<NewLevelType> opNewLevelType = NEW_AS_OWNER_PTR(NewLevelType);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opNewLevelType, L"创建LevelType失败",L"GDMPLab",L"2024-03-30");

        pNewLevelType = opNewLevelType.get();
        pType->GetBasicInformation()->SetName(name);
        pType->GetBasicInformation()->SetCategoryUid(BuiltInCategoryUniIdentities::BICU_NEW_LEVEL_TYPE);

        pNewLevelType->SetOwnerElement(pType);

        // 添加标头类型行为， 并设置默认值
        OwnerPtr<NewLevelHeaderTypeBehavior> opBehavior = NEW_AS_OWNER_PTR(NewLevelHeaderTypeBehavior);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opBehavior, L"创建NewLevelHeaderTypeBehavior失败",L"GDMPLab",L"2024-03-30");
        std::wstring behaviorName = opBehavior->GetName();
        pNewLevelType->AddLevelHeaderTypeBehavior(TransferOwnership(opBehavior));
        pNewLevelType->SetCurrentLevelHeaderTypeBehavior(behaviorName);

        if (IExternalDataComponent * pExternalDataComponent = pType->GetExternalDataComponent())
        {
            pExternalDataComponent->RegisterExternalData(NewLevelType::GetStaticClassSchema()->GetName(), TransferOwnership(opNewLevelType));
        }
    }
    return pNewLevelType;
}

NdbObject* NewLevelType::GetTopOwnerObject() const
{
    return nullptr;
}

const ILevelType* NewLevelType::GetLevelType(IDocument* pDoc, ElementId levelTypeId)
{
    const IGenericType* pType = quick_cast<IGenericType>(pDoc->GetElement(levelTypeId));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pType, L"不是一个GenericType",L"GDMPLab",L"2024-03-30");

    if (const IExternalDataComponent * pExternalDataComponent = pType->GetExternalDataComponent())
    {
        return quick_cast<const ILevelType>(pExternalDataComponent->FindExternalData(NewLevelType::GetStaticClassSchema()->GetName()));
    }
    return nullptr;
}

void gcmp::NewLevelType::UpdateForWeakParentDeletion(const std::set<ElementId>& deletedElementIds)
{
    return;
}

void gcmp::NewLevelType::ReportParents(IElementParentReporter& reporter) const
{
    reporter.ReportStrong(GetOwnerElement()->GetElementId());
}

void NewLevelType::ReportParameterDefinitions(std::vector<int>* pParamDefIds) const
{
    pParamDefIds->push_back(PARAMETER_ID(LevelStartHeaderVisibilityBuiltInParameter));
    pParamDefIds->push_back(PARAMETER_ID(LevelEndHeaderVisibilityBuiltInParameter));
    pParamDefIds->push_back(PARAMETER_ID(LevelHeaderTypeBuiltInParameter));
}

OwnerPtr<IParameter> NewLevelType::GetNativeParameter(int paramDefId) const
{
    ParameterAttributes pa = {false, false, true};
    if (paramDefId == PARAMETER_ID(LevelStartHeaderVisibilityBuiltInParameter))
    {
        //OwnerPtr<IParameter> pParam = NEW_AS_OWNER_PTR(Parameter, GetDocument(),
            //ParameterStorageType::Bool, false, false, true, 
            //PARAMETER_UID(LevelStartHeaderVisibilityBuiltInParameter), ParameterProcessType::GeneralInput);
        OwnerPtr<IParameter> pParam = IParameter::CreateParameter(GetDocument(), ParameterStorageType::Bool,
            pa, PARAMETER_UID(LevelStartHeaderVisibilityBuiltInParameter), ParameterProcessType::GeneralInput);
        pParam->SetValueAsBool(IsStartHeaderVisible());
        return TransferOwnership(pParam);
    }
    else if (paramDefId == PARAMETER_ID(LevelEndHeaderVisibilityBuiltInParameter))
    {
        //OwnerPtr<Parameter> pParam = NEW_AS_OWNER_PTR(Parameter, GetDocument(),
            //ParameterStorageType::Bool, false, false, true, 
            //PARAMETER_UID(LevelEndHeaderVisibilityBuiltInParameter), ParameterProcessType::GeneralInput);
        OwnerPtr<IParameter> pParam = IParameter::CreateParameter(GetDocument(), ParameterStorageType::Bool,
            pa, PARAMETER_UID(LevelEndHeaderVisibilityBuiltInParameter), ParameterProcessType::GeneralInput);
        pParam->SetValueAsBool(IsEndHeaderVisible());
        return TransferOwnership(pParam);
    }

    if (paramDefId == PARAMETER_ID(LevelHeaderTypeBuiltInParameter))
    {
        if (GetCurrentLevelHeaderTypeBehavior())
        {
            //OwnerPtr<Parameter> pParam = NEW_AS_OWNER_PTR(Parameter, GetDocument(),
                //ParameterStorageType::String, false, false, true, 
                //PARAMETER_UID(LevelHeaderTypeBuiltInParameter), ParameterProcessType::GeneralInput);
            OwnerPtr<IParameter> pParam = IParameter::CreateParameter(GetDocument(), ParameterStorageType::String,
                pa, PARAMETER_UID(LevelHeaderTypeBuiltInParameter), ParameterProcessType::GeneralInput);
            pParam->SetValueAsString(GetCurrentLevelHeaderTypeBehavior()->GetName());
            return TransferOwnership(pParam);
        }
    }
    return nullptr;
}

bool NewLevelType::SetNativeParameter(const IParameter *param, std::wstring* errorMsg)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(param, L"param is null.",L"GDMPLab",L"2024-03-30");

    if (param->GetParameterDefinitionId() == PARAMETER_ID(LevelStartHeaderVisibilityBuiltInParameter))
    {
        SetIsStartHeaderVisible__(param->GetValueAsBool());
        return true;
    }
    else if (param->GetParameterDefinitionId() == PARAMETER_ID(LevelEndHeaderVisibilityBuiltInParameter))
    {
        SetIsEndHeaderVisible__(param->GetValueAsBool());
        return true;
    }
    else if (param->GetParameterDefinitionId() == PARAMETER_ID(LevelHeaderTypeBuiltInParameter))
    {
        std::wstring name = param->GetValueAsString();
        if (GetLevelHeaderTypeBehavior(name))
        {
            SetCurrentLevelHeaderTypeBehaviorName__(name);
            UpdateLevelHeaderBehavior();
            return true;
        }
    }
    return false;
}

bool NewLevelType::IsParameterModifiable(int paramDefId) const
{
    return true;
}

IDocument* NewLevelType::GetDocument() const
{
    return GetOwnerElement()->GetDocument();
}

bool NewLevelType::SetCurrentLevelHeaderTypeBehavior(const std::wstring& name)
{
    if (GetLevelHeaderTypeBehaviors__().find(name) != GetLevelHeaderTypeBehaviors__().end())
    {
        SetCurrentLevelHeaderTypeBehaviorName__(name);
        return true;
    }

    return false;
}

const ILevelHeaderTypeBehavior* NewLevelType::GetCurrentLevelHeaderTypeBehavior() const
{
    return GetLevelHeaderTypeBehavior(GetCurrentLevelHeaderTypeBehaviorName__());
}

const ILevelHeaderTypeBehavior* NewLevelType::GetLevelHeaderTypeBehavior(const std::wstring& name) const
{
    auto iter = GetLevelHeaderTypeBehaviors__().find(name);
    if (iter != GetLevelHeaderTypeBehaviors__().end())
    {
        return iter->second.get();
    }

    return nullptr;
}

bool NewLevelType::AddLevelHeaderTypeBehavior(OwnerPtr<ILevelHeaderTypeBehavior> opBehavior)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(opBehavior, L"标高类型行为为空",L"GDMPLab",L"2024-03-30");
    if (GetLevelHeaderTypeBehaviors__().find(opBehavior->GetName()) == GetLevelHeaderTypeBehaviors__().end())
    {
        GetLevelHeaderTypeBehaviorsFW__().insert(make_pair(opBehavior->GetName(), TransferOwnership(opBehavior)));
        return true;
    }

    return false;
}

bool NewLevelType::RemoveLevelHeaderTypeBehavior(const std::wstring& name)
{
    if (GetLevelHeaderTypeBehaviors__().find(name) != GetLevelHeaderTypeBehaviors__().end())
    {
        GetLevelHeaderTypeBehaviorsFW__().erase(name);
        return true;
    }
    return false;
}

std::vector<const ILevelHeaderTypeBehavior*> NewLevelType::GetAllLevelHeaderTypeBehavior() const
{
    std::vector<const ILevelHeaderTypeBehavior*> behaviors;
    FOR_EACH(iter, GetLevelHeaderTypeBehaviors__())
    {
        behaviors.push_back(iter.second.get());
    }

    return behaviors;
}

bool NewLevelType::UpdateLevelHeaderBehavior()
{
    const ILevelHeaderTypeBehavior* pTypeBehavior = GetCurrentLevelHeaderTypeBehavior();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pTypeBehavior, L"当前的ILevelHeaderTypeBehavior为空",L"GDMPLab",L"2024-03-30");

    std::vector<IElement*> allLevels = gcmp::GbmpDocUtils::GetElementsByCategory(GetDocument(), BuiltInCategoryUniIdentities::BICU_NEW_ELEVATION);
    FOR_EACH(pElement, allLevels)
    {
        IGenericElement *pLevelElement = quick_cast<IGenericElement>(pElement);
        if (!pLevelElement || !pLevelElement->GetExternalObject())
        {
            continue;
        }
        ILevel *pLevel = quick_cast<ILevel>(pLevelElement->GetExternalObject());
        if (!pLevel)
        {
            continue;
        }

        pLevel->SetLevelHeaderBehavior(TransferOwnership(pTypeBehavior->CreateLevelHeaderBehavior(pLevelElement)));
    }

    return true;
}